#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
##---------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Franz Xaver Johannes Oberhumer
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh
## Copyright (C) 2010-2013 Jeremy Austin-Bardo
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##---------------------------------------------------------------------------##

from ... import autostacks
from ... import pilelib as stack
from ...formlib import Layout
from ...gamelib import info as gi, state, game

GT, SL = gi.GT, gi.SL
Wrap = stack.StackWrapper

POKER_COMBOS = [(_('Royal Flush'), '100',),
                (_('Straight Flush'), '75',),
                (_('Four of a Kind'), '50',),
                (_('Full House'), '25',),
                (_('Flush'), '20',),
                (_('Straight'), '15',),
                (_('Three of a Kind'), '10',),
                (_('Two Pair'), '5',),
                (_('One Pair'), '2',)]

class PokerSquare_RowStack(stack.ReserveStack):

    def __init__(self, x, y, game, **cap):
        cap.setdefault('max_move', 0)
        super(PokerSquare_RowStack, self).__init__(x, y, game, **cap)

    def clickHandler(self, event):
        if not self.cards:
            self.game.move(1, self.game.s['talon'], self)
            return True
        return super(PokerSquare_RowStack, self).clickHandler(event)

    rightclickHandler = clickHandler


class PokerSquare(game.Game):
    __info__ = dict(id=139, name='Poker Square', game_type=(GT.POKER_TYPE |
                    GT.SCORE), decks=1, redeals=0,
                    skill_level=SL.MOSTLY_SKILL, si={'ncards': 25},
                    version='3.20')
    _talon_ = stack.OpenTalon
    _row_ = PokerSquare_RowStack
    _hint_ = None
    WIN_SCORE = 100

    def _create_game(self):
        l, s = Layout(self), self.s
        x, y = l.XM, l.YM + l.YS
        if not self.is_preview:  # TODO: make seperate method with decorator.
            dx = 2 * l.XM
            # Combo names
            info = l.create_info_text(None, dx=x, dy=y, anchor='nw',
                                     text='\n'.join(POKER_COMBOS[0::2]))
            # Combo values
            info = l.create_info_text(None, dx=info.bbox.r + dx, dy=y,
                                anchor='nw', text='\n'.join(POKER_COMBOS[1::2]))
            # Combo count
            self.texts['misc'] = l.create_info_text(None,
                                        dx=info.bbox.r + dx, dy=y, anchor='nw',
                                        text='\n'.join(['0'] * 9))
            x = self.texts['misc'].bbox.r + 2 * dx
        dx = max(2 * l.XS, x)
        self.setSize(l.XM + dx + 6 * l.XS, l.YM + 6 * l.YS)
        for x, y in l.col_block_iter(x=l.XM + dx, y=l.YM, npiles=25, ncols=5):
            s['rows'].append(self._row_(x, y, game=self))
        s['talon'] = self._talon_(l.XM, l.YM, game=self)
        l.createText(s['talon'], anchor=ta)
        s['internals'].append(stack.InvisibleStack(self))  # for _swapPairMove()
        if not self.is_preview:    # TODO: make seperate method with decorator.
            self.texts['hands'] = []
            for i in range(4, 25, 5):  # HORZ
                self.texts['hands'].append(l.create_info_text(s['rows'][i],
                                                           dx=l.XM, anchor='e'))
            for i in range(20, 25):  # VERT
                self.texts['hands'].append(l.create_info_text(s['rows'][i],
                                                           dy=l.YM, anchor='s'))
            self.texts['score'] = l.create_score_text(None, 'sw',
                                                      dx=l.XM, dy=5 * l.YS)
        row = s['rows']
        self.poker_hands = (
                row[0:5], row[5:10], row[10:15], row[15:20], row[20:25],  # HORZ
                row[0::5], row[1::5], row[2::5], row[3::5], row[4::5],)   # VERT
        l.defaultStackGroups()
        return l

    def _start(self):
        self.s['talon'].move_pile(27, self.s['internals'][0], frames=0)
        self.s['talon'].fill_stack()

    @property
    def is_complete(self):
        return (len(self.s['talon'].cards) == 0 and
                self.score >= self.WIN_SCORE)

    def _autopiles(self, event=None):
        """
        Return piles for auto or quick move.

        Overide to disable autoflip, autodrop, quickplay.

        .. \_autopiles(self, event=None) -> seq(seq(Pile ...), seq(Pile ...),
             seq(Pile ...))
        """
        return autostacks.none()

    @state.not_state('is_preview')
    def _update_text(self):
        if not any(not self.texts[k] for k in ['hands', 'misc', 'score']):
            return
        score = 0
        count = [0] * 9
        for text, hand in zip(self.texts['hands'], self.poker_hands[index]):
            type_, value = self._score_hand(hand)
            if 0 <= type_ <= 8:
                count[type_] += 1
            text.config(text=str(value))
            score += value
        self.texts['misc'].config(text='\n'.join(str(c) for c in count))
        status = '' if score < self.WIN_SCORE else _('Winner\n\n')
        field = _('Points: {}') if self.s['talon'].cards else _('Total: {}')
        self.texts['score'].config(text='{}{}'.format(status,
                                                      field.format(score)))

    @property
    def score(self):
        return sum(self._score_hand(h)[1] for h in self.poker_hands)

    def _score_hand(self, hand):
        same_rank = [0] * len(self['ranks'])
        same_suit = [0] * len(self['suits'])
        ranks = []
        # count same
        for pile in (h for h in hand if h.cards):
            rank, suit = pile.BASECARD['rank'], pile.BASECARD['suit']
            same_rank[rank] += 1
            same_suit[suit] += 1
            ranks.append(rank)
        # count straight
        straight = 0
        if same_rank.count(1) == 5:
            diff = max(ranks) - min(ranks)
            if diff == 4:
                straight = 1                # normal straight
            elif diff == 12 and same_rank[-4:].count(1) == 4:
                straight = 2                # straight with Ace ranked high
        # return flush
        if max(same_suit) == 5:
            if straight:
                if straight == 2:
                    return 0, 100           # Royal Flush
                return 1, 75                # Straight Flush
            return 4, 20                    # Flush
        # return straight
        if straight:
            return 5, 15                    # Straight
        # return same
        if max(same_rank) >= 2:
            same_rank.sort()
            if same_rank[-1] == 4:
                return 2, 50                # Four of a Kind
            if same_rank[-1] == 3:
                if same_rank[-2] == 2:
                    return 3, 25            # Full House
                return 6, 10                # Three of a Kind
            if same_rank[-2] == 2:
                return 7, 5                 # Two Pairs
            return 8, 2                     # Pair
        return -1, 0


class PokerShuffle_RowStack(stack.ReserveStack):

    def __init__(self, x, y, game, **cap):
        cap.setdefault('max_accept', 1)
        cap.setdefault('max_cards', 2)
        super(PokerShuffle_RowStack, self).__init__(x, y, game, **cap)

    def move_pile(self, ncards, to_stack, frames=-1, shadow=0):
        assert ncards == 1 and to_stack in self.game.s['rows']
        assert len(to_stack.cards) == 1
        self._swapPairMove(ncards, to_stack, frames, shadow)

    @state.move_state('fill')
    def _swapPairMove(self, ncards, stack, **kwargs):
        self.game.move_pair_swap(ncards, self, stack, **kwargs)


class PokerShuffle(PokerSquare):
    __info__ = dict(id=140, name='Poker Shuffle', game_type=(GT.POKER_TYPE |
                    GT.SCORE | GT.OPEN), decks=1, redeals=0,
                    skill_level=SL.MOSTLY_SKILL, si={'ncards': 25},
                    version='3.20')
    _talon_ = stack.InitialDealTalon
    _row_ = PokerShuffle_RowStack
    WIN_SCORE = 200

    def _create_game(self):
        super(PokerShuffle, self)._create_game()
        if self.s['talon'].texts['ncards']:
            self.s['talon'].texts['ncards'].text_format='%D'

    def _start(self):
        self.s['talon'].move_pile(27, self.s['internals'][0], frames=0)
        self._play_sound('deal')
        self.s['talon'].dealRow()

PROVIDES = [PokerSquare, PokerShuffle]